﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace COFE.Core.Actions
{


    public class WorkSchedulerAnt : IWorkSchedulerAnt
    {
        #region Constructor

        public WorkSchedulerAnt(IWorkScheduler workScheduler, int id)
        {
            WorkScheduler = workScheduler;
            Id = id;
            _antThread = new Thread(new ParameterizedThreadStart(antProc));
            _antThread.Name = "Ant " + id.ToString();
            _antThread.IsBackground = true;
            _antThread.Priority = ThreadPriority.BelowNormal;            
            _antThread.Start(this);
        }

        #endregion

        #region Methods

        public void Abort()
        {
            _aborting = true;
            if (_currentWork != null)
                _currentWork.Work.Abort();
        }

        static void antProc(object input)
        {
            var ant = input as WorkSchedulerAnt;
            if (ant == null)
                return;
            while (!ant._aborting && !_abortingAll)
            {
                if (ant.Status == WorkAntStatus.Assigned)
                    workProc(ant);
                Thread.Sleep(1000); //One second.
            }
        }

        static void workProc(WorkSchedulerAnt ant)
        {
            IWork work = ant.CurrentSchedule.Work;
            ant.WorkScheduler.EventDispatcher.DispatchEvent(ant, 
                new WorkEventArgs(work, EventType.Started));            
            var workScheduler = ant.WorkScheduler;

            #region Attach events
            work.WorkMessage += ant.OnWorkMessage;
            work.WorkProgress += ant.OnWorkProgress;
            work.WorkFinished += ant.OnWorkFinished;

            #endregion

            COFEShared.UserProfileManager.SetCurrentUserProfile(ant.CurrentSchedule.User);
            work.Start(false); //Started in current thread.            


            #region Detach events
            work.WorkMessage -= ant.OnWorkMessage;
            work.WorkProgress -= ant.OnWorkProgress;
            work.WorkFinished -= ant.OnWorkFinished;

            #endregion

            if (work.Result.Success)
            {
                ant.Status = WorkAntStatus.Success;
                ant.WorkScheduler.EventDispatcher.DispatchEvent(ant,
                    WorkFinishedEventArgs.SuccessArgs(work));
            }
            else
            {
                ant.Status = WorkAntStatus.Failed;
                ant.WorkScheduler.EventDispatcher.DispatchEvent(ant,
                    WorkFinishedEventArgs.FailedArgs(work, work.Result.Error));
            }
        }

        void OnWorkMessage(object sender, WorkMessageEventArgs args)
        {
            if (_aborting || _abortingAll)
                args.Cancel = true;
            WorkScheduler.EventDispatcher.DispatchEvent(CurrentSchedule, args);
        }

        void OnWorkProgress(object sender, WorkProgressEventArgs args)
        {
            if (_aborting || _abortingAll)
                args.Cancel = true;
            //WorkScheduler.OnWorkProgress(sender, args);
        }

        void OnWorkFinished(object sender, WorkFinishedEventArgs args)
        {
            
        }


        private void checkNotWorking()
        {
            switch (Status)
            {
                case WorkAntStatus.Working:
                case WorkAntStatus.Assigned:
                    throw new InvalidOperationException("Another work is running.");
            }
        }

        public void Reset()
        {
            checkNotWorking();
            _currentWork = null;
            Status = WorkAntStatus.Initalized;
        }

        public void AssignWork(ISchedule scheduledWork)
        {
            checkNotWorking();
            _currentWork = scheduledWork;
            Status = WorkAntStatus.Assigned;
        }

        public override string ToString()
        {
            return String.Format("Ant {0}", Id);
        }
        #endregion

        #region Data

        private Thread _antThread;
        private ISchedule _currentWork = null;
        private bool _aborting = false;
        private static bool _abortingAll = false;
        

        #endregion

        #region Public Properties
        
        public IWorkScheduler WorkScheduler { get; private set; }
        public int Id { get; private set; }
        public WorkAntStatus Status { get; private set; }
        public ISchedule CurrentSchedule { get { return _currentWork; } }


        #endregion









    }
}
